package com.aloha.springframework.aop.aspectj.annotation;

import com.aloha.springframework.aop.Advisor;
import com.aloha.springframework.aop.PointcutAdvisor;
import com.aloha.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator;
import com.aloha.springframework.beans.BeansException;
import com.aloha.springframework.beans.factory.config.BeanDefinition;
import org.aspectj.lang.annotation.Aspect;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author DaiZhiHeng
 * @description 为添加 @Aspect 的类创建代理
 * @date 2023/8/2 17:33
 */
public class AnnotationAwareAspectJAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

    private final AspectJAdvisorFactory advisorFactory = new ReflectiveAspectJAdvisorFactory();

    private List<Advisor> cachedAdvisors;

    @Override
    protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) throws BeansException {
        return findCandidateAdvisors()
                .stream()
                .map(advisor -> (PointcutAdvisor) advisor)
                .filter(advisor -> advisor.getPointcut().getClassFilter().matches(beanClass))
                .collect(Collectors.toList());
    }

    @Override
    protected boolean isInfrastructureClass(Class<?> beanClass) {
        return super.isInfrastructureClass(beanClass) || advisorFactory.isAspect(beanClass);
    }

    private List<Advisor> findCandidateAdvisors() {
        if (cachedAdvisors != null) return cachedAdvisors;
        cachedAdvisors = new ArrayList<>();
        advisorFactory.setBeanFactory(beanFactory);
        for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName);
            Class<?> beanClass = beanDefinition.getBeanClass();
            if (!beanClass.isAnnotationPresent(Aspect.class)) continue;
            cachedAdvisors.addAll(advisorFactory.getAdvisors(beanClass));
        }
        return cachedAdvisors;
    }
}
